home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Plus 1999 #2
/
Amiga Plus CD - 1999 - No. 2.iso
/
System-Boost
/
Workbench
/
Archive
/
PP_v1.4
/
Source
/
PP.C
< prev
next >
Wrap
C/C++ Source or Header
|
1998-11-08
|
24KB
|
1,059 lines
/**************************************************************************
*** Powerpacker Patcher ***
Version 1.4
PP is a small utility which enables programs to get at Powerpacked
datafiles in a completely transparent fashion. Any program attempting to
open a Powerpacked datafile will receive the "uncrunched" version of that
file.
This is acomplished by patching some vital DOS functions, thus
redirecting calls to these to my own internal routines. The overall effect
is that Powerpacked datafiles appear as normal files. You can TYPE them in
a CLI window, or bring them directly into your favourite editor. Another
good way to use this proggy is if you crunch your workbench icons.
Workbench will never know the difference, but it reduces the diskspace
occupied by icons by some 65-70% (usually).
Of course, there is a nominal performance reduction in the DOS, which
is caused by the decruncher, but this doesn't seem too annoying.
Especially not if you use optimized (B.A.D.) disks, or increase the size of
the diskbuffers (using the CLI command 'Addbuffers' or equivalent).
For [much] further info, read the DOC file.
Compiles under Aztec V5.0b using large code/large data/32 bit integers.
Should do fine under Lattice, too, if you fix the #pragma's.
Shareware 1991, Copyright (C) 1991 by Michael Berg
Sct. Peders Gade 24A, 2th
8900 Randers
DENMARK
**************************************************************************/
/* That's right -- ALL of these are necessary! */
#include <pragmas.h>
#include <exec/execbase.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/memory.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <workbench/startup.h>
#include <workbench/workbench.h>
/* Well, the compiler has the inline-code ability -- why not use it? */
#define strlen _BUILTIN_strlen
#define strcpy _BUILTIN_strcpy
/* loop construct */
#define FOREVER for(;;)
/* Externals */
extern int myPPLoadData(BPTR,UBYTE **,int *);
extern struct Task *res(char *,int,int (*fptr)(),int);
extern struct MsgPort *myCreatePort(char *,int);
extern void myDeletePort(struct MsgPort *);
extern int addfilenode(BPTR,char *,BPTR);
extern struct filenode *findfilenode(BPTR);
extern void calcsize(char *,short *,short *,short *,short *);
extern char *stoa(short,char *);
extern struct WBStartup *WBenchMsg;
/* Open()-patch related functions */
extern void MakeOpen(void), RestOpen(void);
extern BPTR RealOpen(char *, int);
extern BPTR NewOpen(char *, int);
#pragma regcall(RealOpen(d1,d2)) /* All of these PRAGMAs are EXTREMELY */
#pragma regcall(NewOpen(d1,d2)) /* important !!!!!!!!!! */
/* Close()-patch related functions */
extern void MakeClose(void), RestClose(void);
extern void RealClose(BPTR);
extern void NewClose(BPTR);
#pragma regcall(RealClose(d1))
#pragma regcall(NewClose(d1))
/* Examine()-patch related functions */
extern void MakeExamine(void), RestExamine(void);
extern int RealExamine(BPTR, struct FileInfoBlock *);
extern int NewExamine(BPTR, struct FileInfoBlock *);
#pragma regcall(RealExamine(d1,d2))
#pragma regcall(NewExamine(d1,d2))
/* Write()-patch related functions */
extern void MakeWrite(void), RestWrite(void);
extern int RealWrite(BPTR, char *, int);
extern int NewWrite(BPTR, char *, int);
#pragma regcall(RealWrite(d1,d2,d3))
#pragma regcall(NewWrite(d1,d2,d3))
/* Define the maximum length of a filename and its path.
** 256 is, as far as I can tell, the AmigaDOS (BSTR) limit
*/
#define MAXPATHLEN 256
/* Match tag for PowerPacked files (not encrypted) */
#define PP20 (('P' << 24) + ('P' << 16) + ('2' << 8) + '0')
/* One of these for each opened, powerpacked file, which has not yet been
** closed by the Open()'er.
*/
struct filenode
{
struct MinNode mn;
BPTR filehandle; /* Our new file */
char *new_filename;
BPTR orig_file;
short dirty;
};
/* For inter-process communication */
typedef struct
{
struct Message Msg;
int Result;
/* Additional parameters will live here, eventually */
} MYMSG;
/* Global data */
struct MinList templist;
struct Window *win;
struct IntuitionBase *IntuitionBase;
struct IconBase *IconBase;
int patched, wbmode;
USHORT opencnt,closecnt,examcnt,writecnt;
USHORT pending_exit;
char temppath[MAXPATHLEN];
short vcheck;
struct MsgPort *pp_port;
char *pp_portname = "pp_port";
/* Misc */
char *gbanner = "
Powerpacker Patcher V1.4
\n\
Copyright © 1991, Michael Berg\n
Installation completed
\n";
char *offbanner = "
Powerpacker Patcher V1.4
\n\
Copyright © 1991, Michael Berg\n
Removal completed
\n";
char *wbbanner =
"
Installation trouble?
\n\n\
Simply double-click on my icon, or do an\n\
extended selection
on a disk or drawer\n\
icon (tells me where to put temporary\n\
files). Your AmigaDOS manual will tell\n\
you how to do extended selections.\n";
char *clibanner =
"Syntax: PP [-n] [-c] [<temppath>] ( -c and RAM: are defaults)\n";
char *wbopts =
"My icon contains some
TOOLTYPE
values that\n\I can't make any sense \
of. Select
INFO
from\nthe Workbench menu to fix this.\n";
char *virmsg1 =
"
*** WARNING ***
\n\n The DOS vector for
";
char *virmsg2 =
"() has been changed by someone!\n Your machine may be subject \
to a
link-virus
attack!\n\n I can no longer guarantee \
any kind of DOS integrity and\n protection against virus \
attacks. This is a one-time\n message, from now on you're \
on your own...\n\n Note: A changed vector doesn't have \
to imply a virus\n attack. It is most likely a harmless program \
which is merely\n trying to install itself. I suggest you consult \
your virus\n checker as soon as possible. Just to be sure.\n\n\
Press RETURN ->
";
char *defpath = "RAM:";
void wbmsg(register char *what)
{
register BPTR fh;
short l,t,w,h;
char conspec[40];
char *tmp;
calcsize(what,&l,&t,&w,&h);
strcpy(conspec,"CON:");
tmp = stoa(l,conspec+4);
*tmp++ = '/';
tmp = stoa(t,tmp);
*tmp++ = '/';
tmp = stoa(w,tmp);
*tmp++ = '/';
strcpy(stoa(h,tmp),"/Message From PP");
if (fh = Open(conspec,MODE_NEWFILE))
{
if (IntuitionBase) WBenchToFront();
Write(fh,what,strlen(what));
Delay((3*strlen(what))/2); /* Weird, but works okay */
Close(fh);
}
}
/* Small puts() function (doesn't do a newline, though). If running from
** CLI, print the message in the CLI window. If running from WB, show the
** message in a small console window.
*/
void Say(register char *what)
{
if (wbmode)
wbmsg(what);
else
{
register BPTR out = Output();
/* Do we still have stdout? (CLI may have been closed..) */
if (out)
Write(out,what,strlen(what));
else
wbmsg(what);
}
}
void viruswarn(register char *vect)
{
static short firstmsg = 1;
/* This is an important message. Even if we are running as a CLI
** child, we must open a window for the message to appear in
*/
if (firstmsg && vcheck)
{
register BPTR fh;
char dummy;
firstmsg = 0;
if (fh = RealOpen("CON:72/22/520/148/IMPORTANT MESSAGE FROM PP",MODE_NEWFILE))
{
WBenchToFront();
RealWrite(fh,virmsg1,strlen(virmsg1));
RealWrite(fh,vect,strlen(vect));
RealWrite(fh,virmsg2,strlen(virmsg2));
Read(fh,&dummy,1);
RealClose(fh);
}
}
}
void cleanup()
{
if (IntuitionBase) CloseLibrary(IntuitionBase);
/* Get rid of our port */
if (pp_port)
myDeletePort(pp_port);
/* We have to go to sleep until there are no more tasks executing
** our code
*/
while (opencnt+closecnt+examcnt+writecnt)
Delay(50);
/* Restore the original DOS functions. You will not find these
** functions in the sourcecode. They are generated by the assembler
** macro DOSLibPatch -- see asmsup.c
*/
if (patched)
{
Forbid();
RestOpen();
RestClose();
RestExamine();
RestWrite();
Permit();
}
}
/* Universal termination code */
void die(int doscode,char *errmsg)
{
/* Print the (optional) error message */
if (errmsg)
Say(errmsg);
cleanup();
/* Finally! */
exit(doscode);
}
/* Install the DOS patches */
void installpatch()
{
Forbid();
MakeOpen();
MakeClose();
MakeExamine();
MakeWrite();
Permit();
patched = 1;
}
/* initialize lists */
void initlist()
{
NewList((struct List *)&templist);
}
void doport()
{
if (!(pp_port = myCreatePort(pp_portname,0)))
die(30,"Couldn't create a message port\n");
}
/* passargs passes messages to the 'PP' already running somewhere */
void passargs(register ac, register char **av)
{
MYMSG m;
register struct Process *myself;
myself = (struct Process *)FindTask(0);
m.Msg.mn_Node.ln_Type = NT_MESSAGE;
m.Msg.mn_Length = sizeof(MYMSG);
m.Msg.mn_ReplyPort = &myself->pr_MsgPort;
/* Passing of future parameters go here */
/* Tell him the bad news */
PutMsg(pp_port,(struct Message *)&m);
WaitPort(&myself->pr_MsgPort);
GetMsg(&myself->pr_MsgPort);
if (m.Result)
Say(offbanner);
else
Say("Can't remove PP just yet. Try again a little later!\n");
}
void finalizepath()
{
register char c;
c = temppath[strlen(temppath)-1];
if (c != ':' && c != '/')
strcat(temppath,"/");
}
void badstartup()
{
die(10,wbmode? wbbanner : clibanner);
}
void checkokpath()
{
register BPTR lock;
register char *c;
register allok = 0;
char testdir[MAXPATHLEN];
strcpy(testdir,temppath);
c = testdir + strlen(testdir) - 1;
if (*c == '/') *c = '\0';
if (lock = Lock(testdir,ACCESS_READ))
{
register struct FileInfoBlock *fib;
if (fib = AllocMem(sizeof(*fib),MEMF_CLEAR))
{
if (Examine(lock,fib))
allok = (fib->fib_DirEntryType >= 0);
FreeMem(fib,sizeof(*fib));
}
UnLock(lock);
}
if (!allok)
die(10,"Could not validate your path selection\n");
}
void buildfromlock(register BPTR lock, register char *name)
{
register struct FileInfoBlock *fib;
register BPTR olddir,newlock;
char *fullname();
olddir = CurrentDir(lock);
if (!(newlock = Lock(name,ACCESS_READ)))
{
CurrentDir(olddir);
die(10,"Could not get a lock on your specified path\n");
}
if (fib = AllocMem(sizeof(*fib),MEMF_CLEAR))
{
register retval;
if (retval = Examine(newlock,fib))
strcpy(temppath,fullname(newlock,fib));
UnLock(newlock);
CurrentDir(olddir);
FreeMem(fib,sizeof(*fib));
if (!retval)
die(10,"Cannot examine your path specification\n");
}
else
{
UnLock(newlock);
die(30,"Running low on memory!\n");
}
}
badopts()
{
if (wbmode)
die(30,wbopts);
else
die(30,clibanner);
}
handlecliopts(register ac, register char **av)
{
register short f=0;
register char *tmp;
/* Default flags */
vcheck = 1; /* Check for changing vectors */
for (++av, --ac; ac; ac--, av++)
{
if (**av == '-')
{
while (*(++*av))
{
switch(**av)
{
case 'n' : case 'N' :
vcheck = 0;
continue;
case 'c' : case 'C' :
vcheck = 1;
continue;
default :
return(0);
}
}
}
else
{
switch (f++)
{
case 0 :
strcpy(temppath,*av);
break;
default:
return(0);
}
}
}
if (!f)
strcpy(temppath,defpath);
return(1);
}
parseopt(char *opt)
{
/* The stricmp() function is my own. See 'misc.c' */
if (stricmp(opt,"NOCHECK"))
vcheck = 0;
else if (stricmp(opt,"CHECK"))
vcheck = 1;
else
return(0);
return(1);
}
handlewbopts()
{
struct WBArg *arg = WBenchMsg->sm_ArgList;
int rv = 0;
if (!(IconBase = OpenLibrary("icon.library",0)))
die(30,"Can't open the 'icon.library' (?!)\n");
if (arg->wa_Lock && *arg->wa_Name)
{
char **tooltypes;
struct DiskObject *myicon;
if (myicon = GetDiskObject(arg->wa_Name))
{
for (tooltypes=myicon->do_ToolTypes; *tooltypes; tooltypes++)
rv = parseopt(*tooltypes);
FreeDiskObject(myicon);
}
}
CloseLibrary(IconBase);
return(rv);
}
/* Executed when PP starts up the very first time */
void doinitargs(register ac, register char **av)
{
register char c;
register struct WBArg *arg;
/* So far, the only thing you can tell PP is where to put all
** the temporary files. This defaults to RAM: when no argument
** is given. Workbench argument passing is fully supported.
*/
if (!ac)
{
if (!handlewbopts())
badopts();
switch (WBenchMsg->sm_NumArgs)
{
case 1 : strcpy(temppath,defpath);
break;
case 2 : arg = &WBenchMsg->sm_ArgList[1];
if (arg->wa_Lock)
buildfromlock(arg->wa_Lock,arg->wa_Name);
else
/* Should never happen */
strcpy(temppath,arg->wa_Name);
break;
default: badstartup();
}
}
else
if (!handlecliopts(ac,av))
badopts();
finalizepath();
checkokpath();
}
void openlibs()
{
if (!(IntuitionBase = OpenLibrary("intuition.library",0)))
die(30,"Missing 'intuition.library'\n");
}
/* Open up everything */
void openstuff(register ac, register char **av)
{
openlibs();
if (pp_port = FindPort(pp_portname))
{
/* There's already a working copy of PP running somewhere.
** Pass the arguments along to it, and then exit.
*/
passargs(ac,av);
/* Don't let die() remove the port */
pp_port = NULL;
die(0,NULL);
}
/* This is the first time around. Install everything */
doinitargs(ac,av);
initlist();
installpatch();
doport();
}
/* This baby builds a complete filename (including a path) from a BCPL
** pointer to a filehandle. Optimizations are most welcome. All those
** ParentDir() calls take a LONG time.
*/
char *fullname(register BPTR lock, register struct FileInfoBlock *fib)
{
static char pathandfile[MAXPATHLEN];
char tmp[MAXPATHLEN];
register BPTR parentlock, unlocklock;
register char *co;
strcpy(pathandfile,fib->fib_FileName);
parentlock = lock;
unlocklock = (BPTR)0;
while (parentlock = ParentDir(parentlock))
{
if (unlocklock)
UnLock(unlocklock);
if (patched? RealExamine(parentlock,fib) : Examine(parentlock,fib))
{
strcpy(tmp,fib->fib_FileName);
strcat(tmp,"/");
strcat(tmp,pathandfile);
strcpy(pathandfile,tmp);
}
else
{
UnLock(parentlock);
return(NULL);
}
unlocklock = parentlock;
}
if (unlocklock)
{
UnLock(unlocklock);
if (co = (char *)index(pathandfile,'/'))
*co = ':';
}
else
strcat(pathandfile,":");
/* This fixes a bug in the old RAM disk */
if (!strcmp(pathandfile,":"))
strcpy(pathandfile,"RAM:");
return(pathandfile);
}
reallyfile(register BPTR handle)
{
return (!IsInteractive(handle));
}
/* When somebody opens a PP file, we decrunch it into a temporary file
** and return a filehandle to that file. When the caller closes the file
** (which he thinks is the original disk file), he will really be closing
** the temporary file. This is a good chance for us to get rid of it,
** so that the temporary directory won't get crowded in time. HOWEVER!
** If the caller has written new data into the file, we have to rewrite the
** temporary file over the original (disk) file. flushout() does exactly
** that.
*/
void flushout(register struct filenode *fn)
{
register BPTR orighandle;
char buffer[2048]; /* Should suffice */
register short readlen;
Seek(fn->filehandle, 0, -1); /* Our file */
Seek(fn->orig_file,0,-1); /* The original file */
do
{
readlen = Read(fn->filehandle, buffer, 2048);
RealWrite(fn->orig_file, buffer, readlen);
}
while (readlen == 2048);
}
/* Look for a powerpacker matchtag at the beginning of a file. Returns TRUE
** if the file was indeed a powerpacker datafile.
*/
isppfile(register BPTR fh)
{
int ppmatchtag;
/* This function leaves the file position ptr. at 0 for non-PP files */
Read(fh,(char *)&ppmatchtag,sizeof(int));
if (ppmatchtag == PP20)
return(1);
else
{
Seek(fh,0,-1);
return(0);
}
}
closedel(register BPTR tempfh,register char *filnambuf)
{
RealClose(tempfh);
DeleteFile(filnambuf);
}
BPTR xNewOpen(register char *filename, register mode)
{
UBYTE *memgot;
int filelen;
register BPTR tempfh,origfile;
register struct Task *thistask;
origfile = tempfh = RealOpen(filename,mode);
/* We only deal with a few of the incoming calls:
**
** 1) Files which CAN in fact be opened
** 2) We can't do anything about new files
** 3) Equally, we don't care about CON: or NIL: file open requests
** 4) We don't care about non-crunched files
*/
if
(
!tempfh ||
mode == MODE_NEWFILE ||
!reallyfile(tempfh) ||
!isppfile(tempfh)
)
return(tempfh);
/* Now, ask ppLoadData to bring in the file */
if (!myPPLoadData(tempfh,&memgot,&filelen))
{
char filnambuf[MAXPATHLEN];
register char *t, *m;
/* Generate a name for the temporary file */
t = filename;
if (m = (char *)index(t,':')) t = m+1;
while (m = (char *)index(t,'/')) t = m+1;
strcpy(filnambuf,temppath);
strcat(filnambuf,t);
strcat(filnambuf,".tmp");
/* We have to ensure that the name is unique on 'temppath' */
while (tempfh = RealOpen(filnambuf,MODE_OLDFILE))
{
char *xtra = "?";
/* Pad the name with random characters. This
** should do the trick
*/
RealClose(tempfh);
*xtra = 'A' + (rand() % 26);
strcat(filnambuf,xtra);
}
/* Now, open the temporary file and flush data we loaded into
** this file.
*/
if (tempfh = RealOpen(filnambuf,MODE_NEWFILE))
{
register short w_err = 0;
/* Write the decrunched data to our new file. We
** do this by writing a bit, then freeing a bit,
** then writing the next bit -- and so forth.
** When the temporary path is in RAM:, this is
** a very good way to keep PP from using too much
** memory at a time. (Read .DOC file for further
** details)
*/
/* Chop it up in 10k slices
** - and DON'T try to change that!
*/
while (filelen > 10239 && !w_err)
{
w_err = (RealWrite(tempfh,(char *)memgot,10240) != 10240);
FreeMem(memgot,10240);
filelen -= 10240;
memgot += 10240;
}
if (w_err)
{
closedel(tempfh,filnambuf);
tempfh = origfile;
goto quitout;
}
/* Do the final odd-length slice, if any */
if (filelen)
{
w_err = (RealWrite(tempfh,(char *)memgot,filelen) != filelen);
FreeMem(memgot,filelen);
if (w_err)
{
closedel(tempfh,filnambuf);
tempfh = origfile;
goto quitout;
}
}
/* We need to reopen the file in "MODE_OLDFILE" */
RealClose(tempfh);
tempfh = RealOpen(filnambuf,MODE_OLDFILE);
/* Remember that WE created that file */
if (!addfilenode(tempfh,filnambuf,origfile))
{
/* Couln't do it. Return original filehandle */
closedel(tempfh,filnambuf);
tempfh = origfile;
}
}
else
{
/* Housekeeping */
FreeMem(memgot,filelen);
/* Return original file */
tempfh = origfile;
}
}
quitout:
/* Return a filehandle to the file (ours or the original) */
Seek(tempfh,0,-1);
return(tempfh);
}
/* This is the new Open() functions. All future calls to the DOS Open()
** function will be rerouted through here.
*/
BPTR NewOpen(register char *filename, register mode)
{
register BPTR retval;
if (CheckOpen()) viruswarn("Open");
if (pending_exit)
return(RealOpen(filename,mode));
opencnt++;
retval = xNewOpen(filename,mode);
opencnt--;
return(retval);
}
int xNewWrite(register BPTR filehandle, register char *buffer, int length)
{
register struct filenode *fn;
register wrtret;
wrtret = RealWrite(filehandle, buffer, length);
if (fn = findfilenode(filehandle))
fn->dirty = 1;
return(wrtret);
}
/* Yep! A new Write() function. We have to know if a process has updated
** the (substitute) file we created for it. If true, mark the file as
** being "dirty", so that we can later save it over the original PP file.
*/
int NewWrite(register BPTR filehandle, register char *buffer, int length)
{
register retval;
if (CheckWrite()) viruswarn("Write");
if (pending_exit)
return(RealWrite(filehandle,buffer,length));
writecnt++;
retval = xNewWrite(filehandle,buffer,length);
writecnt--;
return(retval);
}
void xNewClose(register BPTR filehandle)
{
register struct filenode *fn;
if (fn = findfilenode(filehandle))
{
Forbid();
Remove((struct Node *)fn);
Permit();
if (fn->dirty)
flushout(fn);
RealClose(fn->orig_file);
RealClose(filehandle);
DeleteFile(fn->new_filename);
FreeMem(fn->new_filename,strlen(fn->new_filename)+1);
FreeMem(fn,sizeof(*fn));
}
else
RealClose(filehandle);
}
/* A new Close() function. It removes non-dirty, temporary files from
** 'temppath', and it keeps track of which files have to be updated back
** onto disk.
*/
void NewClose(register BPTR filehandle)
{
if (CheckClose()) viruswarn("Close");
if (pending_exit)
RealClose(filehandle);
else
{
closecnt++;
xNewClose(filehandle);
closecnt--;
}
}
int xNewExamine(BPTR lock, struct FileInfoBlock *fib)
{
int decrunchinfo;
register examinereturn;
register BPTR tmpfh;
struct FileInfoBlock fib_backup;
/* Start off by examining the lock */
if (!(examinereturn = RealExamine(lock,fib)))
return(0);
/* If it's a directory, never mind */
if (fib->fib_DirEntryType >= 0)
return(examinereturn);
/* The lock target was a simple file. Check to see if it's a
** PP file
*/
fib_backup = *fib;
tmpfh = RealOpen(fullname(lock,fib),MODE_OLDFILE);
*fib = fib_backup;
if (!tmpfh)
return(examinereturn);
if (isppfile(tmpfh))
{
/* It was. Examine decrunchinfo to get at the original
** filesize, so that programs trying to allocate enough
** memory to hold a certain file will get the correct
** filesize (which is, of corz, size of the decrunched
** file!)
*/
Seek(tmpfh,-4,1);
Read(tmpfh,(char *)&decrunchinfo,sizeof(int));
fib->fib_Size = decrunchinfo >> 8;
}
RealClose(tmpfh);
return(examinereturn);
}
/* A new Examine() function. Often, programs examine a file before opening
** it. This way, they can allocate just enough memory to hold the entire
** file. However, we have to correct Examine() calls to PowerPacked files,
** so that the correct amount of memory will be allocated by the caller.
*/
int NewExamine(BPTR lock, struct FileInfoBlock *fib)
{
register retval;
if (CheckExamine()) viruswarn("Examine");
if (pending_exit)
return(RealExamine(lock,fib));
examcnt++;
retval = xNewExamine(lock,fib);
examcnt--;
return(retval);
}
maydie()
{
Forbid();
pending_exit = !(templist.mlh_Head->mln_Succ)
&& !(opencnt | closecnt | examcnt | writecnt)
&& !(CheckOpen() | CheckClose() | CheckExamine() | CheckWrite());
Permit();
return(pending_exit);
}
/* Hangaround() waits for messages to arrive at our port, and then deals
** with them. This routine could be written in a much smaller version, but
** I've written it so that it will be easy to add more 'commands'.
*/
int hangaround()
{
register MYMSG *m;
pp_port->mp_SigTask = FindTask(0);
FOREVER
{
WaitPort(pp_port);
while (m = (MYMSG *)GetMsg(pp_port))
{
short candie;
/* Eventually, some kind of actual communication
** will take place here. In this version, we simply
** quit whenever we spot an incoming message.
*/
if (candie = maydie())
m->Result = 1;
else
m->Result = 0;
ReplyMsg((struct Message *)m);
if (candie)
{
cleanup();
return(0);
}
}
}
}
/* Entry point */
void main(int argc, char *argv[])
{
wbmode = (argc == 0);
openstuff(argc,argv);
if (!wbmode)
{
if (!res("Powerpacker Patcher",0,hangaround,4000))
die(30,"Can't spawn background process!\n");
else
/* Tell the world the good news (CLI) */
Say(gbanner);
}
else
{
/* Tell the world the good news (Workbench) */
Say(gbanner);
hangaround();
}
}